package com.qriver.oauth.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.client.BaseClientDetails;
import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices;
import org.springframework.security.oauth2.provider.code.InMemoryAuthorizationCodeServices;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;

/**
 * 授权服务器 配置
 */
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private TokenStore tokenStore;

    @Autowired
    private ClientDetailsService clientDetailsService;

    @Autowired
    private PasswordEncoder passwordEncoder;

    /**
     * 配置 Token 的一些基本信息
     * @return
     */
    @Bean
    AuthorizationServerTokenServices tokenServices(){
        DefaultTokenServices services = new DefaultTokenServices();
        services.setClientDetailsService(clientDetailsService);//配置客户端校验方式
        services.setReuseRefreshToken(true);//设置Token是否支持刷新
        services.setTokenStore(tokenStore);//设置Token的存储位置
        services.setAccessTokenValiditySeconds(60 * 60 * 2);//设置Token有效期
        services.setRefreshTokenValiditySeconds(60 * 60 * 24 * 7);//设置Token刷新有效期
        return services;
    }

    /**
     * 配置令牌端点的安全约束
     * @param security
     * @throws Exception
     */
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security.checkTokenAccess("permitAll()")//Token 校验的端点，后续客户端验证Token使用
                .allowFormAuthenticationForClients()
                .passwordEncoder(passwordEncoder);
    }

    /**
     * 配置客户端的详细信息，客户端信息可以存储数据库、内存等地方
     * @param clients
     * @throws Exception
     */
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        //clientId,resourceIds,scopes,grantTypes,authorities
        clients.inMemory().withClient("client1")//配置clientId，唯一标识，表示客户端，即第三方应用
                .secret(new BCryptPasswordEncoder().encode("123456"))//客户端访问密码
                .autoApprove(true)
               // .resourceIds("res-1")//客户端所能访问的资源id集合
                //客户端支持的grant_type,可选值包括authorization_code,password,refresh_token,implicit,client_credentials, 若支持多个grant_type用逗号(,)分隔
                .authorizedGrantTypes("authorization_code","refresh_token")
                //客户端申请的权限范围,可选值包括read,write,trust;若有多个权限范围用逗号(,)分隔
                .scopes("all")
                //客户端的重定向URI
                .redirectUris("http://localhost:8082/login")
              .and()
                .withClient("client2")
                .secret(new BCryptPasswordEncoder().encode("123456"))//客户端访问密码
                .autoApprove(true)
               // .resourceIds("res-2")//客户端所能访问的资源id集合
                //客户端支持的grant_type,可选值包括authorization_code,password,refresh_token,implicit,client_credentials, 若支持多个grant_type用逗号(,)分隔
                .authorizedGrantTypes("authorization_code","refresh_token")
                //客户端申请的权限范围,可选值包括read,write,trust;若有多个权限范围用逗号(,)分隔
                .scopes("all")
                //客户端的重定向URI
                .redirectUris("http://localhost:8083/login")
                 .and()
                .withClient("resource1")
                .secret(new BCryptPasswordEncoder().encode("123456"));
    }

    /**
     * 配置令牌的访问端点和令牌服务
     * @param endpoints
     * @throws Exception
     */
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.authorizationCodeServices(authorizationCodeServices())
                .tokenServices(tokenServices());
    }

    /**
     * 配置授权码的存储
     * @return
     */
    @Bean
    AuthorizationCodeServices authorizationCodeServices(){
        return new InMemoryAuthorizationCodeServices();
    }
}
